﻿using System.ComponentModel;
using System.Runtime.Serialization;
using Navigant.Common;

namespace Navigant.DataContracts
{
    [DataContract(Name = "ContractBase", Namespace = ServiceConstants.DataContractNamespace)]
    public abstract class ContractBase : INotifyPropertyChanged
    {
        #region Fields

        private int key;

        #endregion

        #region Properties

        [DataMember]
        public int Key
        {
            get
            {
                return this.key;
            }
            set
            {
                if (!object.ReferenceEquals(this.key, value))
                {
                    this.key = value;
                    this.RaisePropertyChanged("Key");
                }
            }
        }

        #endregion

        #region RaisePropertyChanged

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            this.RaisePropertyChanged(this, propertyName);
        }

        private void RaisePropertyChanged(object sender, string propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if ((propertyChanged != null))
            {
                propertyChanged(sender, new PropertyChangedEventArgs(propertyName));
            }
        }

        public void RaisePropertyChanged<T>(T originalSender, T modifiedSender, string propertyName)
        {
            PropertyChangedEventArgsSender<T> sender = new PropertyChangedEventArgsSender<T>()
            {
                New = modifiedSender,
                Original = originalSender
            };
            this.RaisePropertyChanged(sender, propertyName);
        }

        #endregion

        #region Equality Tests

        /// <summary>
        /// Determines whether the specified entity is equal to the 
        /// current instance.
        /// </summary>
        /// <param name="entity">An <see cref="System.Object"/> that 
        /// will be compared to the current instance.</param>
        /// <returns>True if the passed in entity is equal to the 
        /// current instance.</returns>
        public override bool Equals(object contract)
        {
            return contract != null
                && contract is ContractBase
                && this == (ContractBase)contract;
        }

        /// <summary>
        /// Operator overload for determining equality.
        /// </summary>
        /// <param name="base1">The first instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="base2">The second instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if equal.</returns>
        public static bool operator ==(ContractBase base1,
            ContractBase base2)
        {
            // check for both null (cast to object or recursive loop)
            if ((object)base1 == null && (object)base2 == null)
            {
                return true;
            }

            // check for either of them == to null
            if ((object)base1 == null || (object)base2 == null)
            {
                return false;
            }

            // Make sure the Key values match
            if (base1.Key != base2.Key)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Operator overload for determining inequality.
        /// </summary>
        /// <param name="base1">The first instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="base2">The second instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if not equal.</returns>
        public static bool operator !=(ContractBase base1,
            ContractBase base2)
        {
            return (!(base1 == base2));
        }

        /// <summary>
        /// Serves as a hash function for this type.
        /// </summary>
        /// <returns>A hash code for the current Key 
        /// property.</returns>
        public override int GetHashCode()
        {
            return this.Key.GetHashCode();
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
